package org.apache.dolphinscheduler.api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.api.client.util.Lists;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.CouponbillService;
import org.apache.dolphinscheduler.api.service.UserGroupService;
import org.apache.dolphinscheduler.api.service.UsersService;
import org.apache.dolphinscheduler.api.utils.ExcelUtil;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.api.vo.CouponbillExportVo;
import org.apache.dolphinscheduler.dao.entity.Couponbill;
import org.apache.dolphinscheduler.dao.entity.Coupondetail;
import org.apache.dolphinscheduler.dao.vo.CouponBillVo;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.CouponbillMapper;
import org.apache.dolphinscheduler.dao.mapper.CoupondetailMapper;
import org.apache.dolphinscheduler.dao.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 收支明细表 服务实现类
 * </p>
 *
 * @author denggh
 * @since 2023-08-14
 */
@Service
public class CouponbillServiceImpl extends BaseServiceImpl implements CouponbillService {

    @Autowired
    private CouponbillMapper CouponbillMapper;
    @Autowired
    private CoupondetailMapper coupondetailMapper;
    @Autowired
    private UsersService userService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserGroupService userGroupService;

    @Override
    public Result selectPageCouponbillList(User loginUser, Couponbill couponbill, String issueTpye,  String startDateClaim, String endDateClaim, String startDateUse, String endDateUse, String startDateEnd, String endDateEnd, Integer pageSize, Integer pageNo) {
        Result result = new Result();
        PageInfo<CouponBillVo> pageInfo = new PageInfo<>(pageNo, pageSize);

        Page<CouponBillVo> page = new Page<>(pageNo, pageSize);

        List<Integer> userIdList = Lists.newArrayList();
        // 如果不是管理员角色 只能查询当前用户收支明细
        // 如果用户是用户组管理员 可以查询用户组下所有用户的数据
        if (!isAdmin(loginUser)) {
            userIdList.add(loginUser.getId());
            List<Integer> userIds = userGroupService.queryAllUserByGroupAdmin(loginUser);
            if(CollectionUtils.isNotEmpty(userIds)){
                userIdList.addAll(userIds);
            }
        }

        IPage<CouponBillVo> couponBillVoList = CouponbillMapper.selectCouponbillPage(page, couponbill.getCoupondetailId(), couponbill.getCouponName(), couponbill.getCouponState(), couponbill.getBillNo(), couponbill.getUseAccount(), userIdList, issueTpye, startDateClaim, endDateClaim, startDateUse, endDateUse, startDateEnd, endDateEnd);
        pageInfo.setTotal((int) couponBillVoList.getTotal());
        pageInfo.setTotalList(couponBillVoList.getRecords());
        result.setData(pageInfo);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    public Result selectCouponRule(Integer id){
        Result result = new Result();
        result.setData(coupondetailMapper.selectById(id));
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result getCouponbillTable(Integer id) {
        Result result = new Result();
        Map<String, Object> resultMap = new HashMap<>();

        //获得发放总量
        Coupondetail coupondetail = coupondetailMapper.selectById(id);
        Integer grantNum = coupondetail.getSendNum();
        Integer useNum = coupondetail.getUseNum();
        resultMap.put("grantNum", grantNum);
        resultMap.put("useNum", useNum);
        resultMap.put("noUseNum", grantNum-useNum);
        resultMap.put("unclaimNum", grantNum-useNum);
        Integer claimNum = useNum;
        resultMap.put("claimNum", claimNum);
        if (coupondetail.getIssueType().equals("平台发放")) {
            claimNum = grantNum;
            resultMap.put("claimNum", claimNum);
        }

        //已过期 = 已失效
        LocalDateTime now = LocalDateTime.now();
        LambdaQueryWrapper<Couponbill> lqwTime = new LambdaQueryWrapper<>();
        lqwTime.eq(Couponbill::getCoupondetailId, id)
                .ne(Couponbill::getCouponState, "已使用")
                .lt(Couponbill::getEndTime, now);
        Long expireNum = CouponbillMapper.selectCount(lqwTime);
        resultMap.put("expireNum", expireNum);
        resultMap.put("endNum", expireNum);

        //领取率
        BigDecimal claimRate =
                (new BigDecimal(claimNum)).divide(BigDecimal.valueOf(grantNum), 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100));
        resultMap.put("claimRate", claimRate);
        //使用率
        BigDecimal useRate =  (new BigDecimal(useNum)).divide(BigDecimal.valueOf(grantNum), 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100));
        resultMap.put("useRate", useRate);

        //用券用户 = 拉新用户数
        Integer userNum = CouponbillMapper.getTotalUserNum(id);
        resultMap.put("userNum", userNum);
        resultMap.put("newUserNum", userNum);

        //总应付金额
        BigDecimal payable = CouponbillMapper.getTotalPayableAmount(id);
        payable = (payable == null) ? new BigDecimal("0.00") : payable;
        //总实付金额
        BigDecimal payment = CouponbillMapper.getTotalPaymentAmount(id);
        payment = (payment == null) ? new BigDecimal("0.00") : payment;
        //优惠总金额
        BigDecimal preferentialAmount = new BigDecimal("0.00");
        preferentialAmount = payable.subtract(payment);
        resultMap.put("couponAmount", payment);
        resultMap.put("preferentialAmount", preferentialAmount);

        result.setData(resultMap);
        putMsg(result, Status.SUCCESS);
        return result;

    }

    @Override
    public Result getUserCouponbills(User loginUser, Integer searchType) {
        Result result = new Result();
        List<Map<String, Object>> resultList = new ArrayList<>();

        LocalDateTime now = LocalDateTime.now();
        LambdaQueryWrapper<Couponbill> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Couponbill::getUseAccount, loginUser.getId());
        switch (searchType) {
            //待使用
            case 0:
                lqw.ge(Couponbill::getEndTime, now)
                        .eq(Couponbill::getCouponState, "未使用");
                break;

            //已使用
            case 1:
                lqw.eq(Couponbill::getCouponState, "已使用");
                break;

            //已失效
            case 2:
                lqw.lt(Couponbill::getEndTime, now)
                        .ne(Couponbill::getCouponState, "已使用");
                break;
        }
        List<Couponbill> couponbills = CouponbillMapper.selectList(lqw);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
        for (Couponbill temp : couponbills) {
            Map<String, Object> resultMap = new HashMap<>();
            Coupondetail curDetail = coupondetailMapper.selectById(temp.getCoupondetailId());
            resultMap.put("couponName", curDetail.getCouponName());
            resultMap.put("couponValue", curDetail.getUseRuledeno());
            resultMap.put("useRule", curDetail.getUseRule());
            resultMap.put("startTime", sdf.format(temp.getClaimTime()));
            resultMap.put("endTime", sdf.format(temp.getEndTime()));
            resultList.add(resultMap);
        }
        result.setData(resultList);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result getAvailableCoupon(User loginUser, Integer amount, String billNo, Integer billType) {
        Result result = new Result();
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (billType == 0) {
            List<Map<String,Object>> couponBillList = CouponbillMapper.getAvailablePlatCoupon(amount, loginUser.getId());
            List<Map<String,Object>> couponDetailList = CouponbillMapper.getAvailableCollectCoupon(amount);
            resultList.addAll(couponBillList);
            resultList.addAll(couponDetailList);
        } else {
            List<Map<String,Object>> usedCoupon = CouponbillMapper.getUsedCouponBill(billNo);
            resultList.addAll(usedCoupon);
        }

        result.setData(resultList);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public void updateCouponbillByDetailId(Couponbill couponbill, Coupondetail coupondetail) {
        Integer couponDetailId = couponbill.getCoupondetailId();
        LambdaQueryWrapper<Couponbill> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Couponbill::getCoupondetailId, couponDetailId)
                .eq(Couponbill::getUseAccount, couponbill.getUseAccount())
                .eq(Couponbill::getCouponState, "未使用");
        List<Couponbill> list = CouponbillMapper.selectList(lqw);
        Date now = new Date();
        couponbill.setUseTime(now);
        if (list.size() == 0) {
            couponbill.setCouponNo(coupondetail.getCouponNo());
            couponbill.setCouponName(coupondetail.getCouponName());
            couponbill.setClaimTime(now);
            couponbill.setEndTime(coupondetail.getSendEndTime());
            CouponbillMapper.insert(couponbill);
        } else {
            couponbill.setId(list.get(0).getId());
            CouponbillMapper.updateById(couponbill);
        }
        coupondetail.setUseNum(coupondetail.getUseNum()+1);
        coupondetailMapper.updateById(coupondetail);
    }

    @Override
    public void exportExcel(User loginUser, Couponbill couponbill, String startDateClaim, String endDateClaim, String startDateUse, String endDateUse, String startDateEnd, String endDateEnd, HttpServletResponse response) {
        LambdaQueryWrapper<Couponbill> lqw = new LambdaQueryWrapper<>();

        List<Integer> userIdList = Lists.newArrayList();
        // 如果不是管理员角色 只能查询当前用户收支明细
        // 如果用户是用户组管理员 可以查询用户组下所有用户的数据
        if (!isAdmin(loginUser)) {
            userIdList.add(loginUser.getId());
            List<Integer> userIds = userGroupService.queryAllUserByGroupAdmin(loginUser);
            if(CollectionUtils.isNotEmpty(userIds)){
                userIdList.addAll(userIds);
            }
        }

        // 算力券id
        if (Objects.nonNull(couponbill.getCoupondetailId())&&!("".equals(couponbill.getCoupondetailId()))){
            lqw.eq(Couponbill::getCoupondetailId, couponbill.getCoupondetailId());
        }
        // 算力券状态
        if (Objects.nonNull(couponbill.getCouponState())&&!("".equals(couponbill.getCouponState()))){
            lqw.eq(Couponbill::getCouponState, couponbill.getCouponState());
        }
        System.out.println(couponbill.getCouponState());
        // 交易类型
        if (Objects.nonNull(couponbill.getBillNo())&&!("".equals(couponbill.getBillNo()))) {
            lqw.eq(Couponbill::getBillNo, couponbill.getBillNo());
        }
        //使用用户
        if (Objects.nonNull(couponbill.getUseAccount())&&!("".equals(couponbill.getUseAccount()))) {
            lqw.eq(Couponbill::getUseAccount, couponbill.getUseAccount());
        }
        // 领取——开始时间
        if (StringUtils.isNotBlank(startDateClaim)) {
            lqw.ge(Couponbill::getClaimTime, startDateClaim);
        }
        // 领取——结束时间
        if (StringUtils.isNotBlank(endDateClaim)) {
            lqw.lt(Couponbill::getClaimTime, endDateClaim);
        }
        // 使用——开始时间
        if (StringUtils.isNotBlank(startDateUse)) {
            lqw.ge(Couponbill::getUseTime, startDateUse);
        }
        // 使用——结束时间
        if (StringUtils.isNotBlank(endDateUse)) {
            lqw.lt(Couponbill::getUseTime, endDateUse);
        }
        // 过期——开始时间
        if (StringUtils.isNotBlank(startDateEnd)) {
            lqw.ge(Couponbill::getEndTime, startDateEnd);
        }
        // 过期——结束时间
        if (StringUtils.isNotBlank(endDateEnd)) {
            lqw.lt(Couponbill::getEndTime, endDateEnd);
        }
        lqw.orderByDesc(Couponbill::getUseTime);
        List<Couponbill> couponbillList = CouponbillMapper.selectList(lqw);

        List<CouponbillExportVo> exportVoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(couponbillList)) {
            exportVoList = couponbillList.stream().map(it -> {
                CouponbillExportVo couponbillExportVo = new CouponbillExportVo();
                try {
                    BeanUtils.copyProperties(couponbillExportVo, it);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return couponbillExportVo;
            }).collect(Collectors.toList());
        }

        ExcelUtil.exportExcel(exportVoList, "算力券订单明细", CouponbillExportVo.class, response);

    }

    @Override
    public Result selectCouponUsedTotal(User loginUser, String month) {
        Result result = new Result();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d"); // 设置日期格式
        System.out.println(month);
        LocalDate localDate = LocalDate.parse(month+"-1", formatter);
        LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());

        long all = coupondetailMapper.countAllCouponNums(firstDayOfMonth.toString(), lastDayOfMonth.toString());

        LambdaQueryWrapper<Couponbill> lqw = new LambdaQueryWrapper<>();
        lqw.between(Couponbill::getClaimTime, firstDayOfMonth, lastDayOfMonth);
        lqw.eq(Couponbill::getCouponState, "已使用");
        long used = CouponbillMapper.selectCount(lqw);

        List<Long> coupon=new ArrayList<>();
        coupon.add(all - used);
        coupon.add(used);
        result.setData(coupon);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    /**
     * 插入为指定用户插入couponbill并返回sendnum
     * @param couponDetailId
     * @return
     */
    @Override
    public Integer addCouponBillByTimeTask(Integer couponDetailId) {
        Coupondetail coupondetail = coupondetailMapper.selectById(couponDetailId);
        List<String> userIds = userService.allUsersIdList();
        Integer ignored = coupondetail.getUseLimit();
        for (int i = 0 ; i < ignored; i++) {
            CouponbillMapper.insertCouponBills(userIds, coupondetail);
        }
        return userIds.size()*coupondetail.getUseLimit();
    }


}
